package postpc.powerreminders.com.location;

import java.util.List;

import android.location.Location;
import android.net.wifi.ScanResult;
import android.util.Log;


public class RotgPowerManager {

	/*
	 * Power Levels
	 */
	public final static int POWER_LEVEL_NONE 	= 0;
	public final static int POWER_LEVEL_NORMAL 	= 1;
	public final static int POWER_LEVEL_LOW 	= 2;
	public final static int POWER_LEVEL_HIGH 	= 3;

	/*
	 * Power Levels variables
	 */
	private static double SAME_LOCATION_MULTIPLIER 	= 2;
	private static double CLOSE_LOCATION_MULTIPLIER = 1.5;
	private static double MATCH_TRESH_PERCENT 		= 0.6;

	private static final long DEFAULT_SCAN_TIME = 3000;

	/*
	 * Power Manager fields
	 */
	List<ScanResult> lastResults;

	/*
	 * Last location - used for next update calculations. 
	 */
	Location lastLocation;

	/*
	 * Logger tag
	 */
	private static final String TAG = "ROTG_PowerManager";

	private static final long MAX_WIFI_TIMEOUT = 60000;
	private static final float GPS_MIN_DISTANCE = 30;
	private static final long GPS_MAX_UPDATE_TIME = 100000;

	/*
	 * GPS power management variables 
	 */
	long minTime = 1;
	float minDistance = 1;
	long wifiScanInterval;
	int powerLevel;
	private boolean gps_disable = false;

	/**
	 * 
	 * @param minTime
	 * @param minDistance
	 * @param wifiScanInterval
	 * @param level
	 */
	public RotgPowerManager(long minTime, float minDistance, long wifiScanInterval, int level) {

		Log.i(TAG, "Creating power manager with level: " + level);
		this.minTime = minTime;
		this.minDistance = minDistance;
		this.wifiScanInterval = wifiScanInterval;
		this.powerLevel = level;

	}

	public RotgPowerManager(int level) {
		this(3000, 1, DEFAULT_SCAN_TIME, level);
	}

	public RotgPowerManager() {
		this(1000, 1, DEFAULT_SCAN_TIME, POWER_LEVEL_NORMAL);
	}

	public long getMinTime() {
		return minTime;
	}

	public void setMinTime(long minTime) {
		this.minTime = minTime;
	}

	public float getMinDistance() {
		return minDistance;
	}

	public void setMinDistance(float minDistance) {
		this.minDistance = minDistance;
	}

	/**
	 * Returns the WiFi scan interval.
	 * 
	 * @return -1 if WiFi should be shut down
	 */
	public long getWifiScanInterval() {
		Log.i(TAG, "Wifi Scan Interval: " + this.wifiScanInterval);
		return this.wifiScanInterval;
	}

	public void setWifiScanInterval(long wifiScanInterval) {
		this.wifiScanInterval = wifiScanInterval;
	}

	/**
	 * 
	 * @param results
	 */
	public synchronized void evaluateWifi(List<ScanResult> results) {
		int stored = 0;
		Log.i (TAG, "Evaluating WIFI");
		if (null == this.lastResults){
			this.lastResults = results;
			return;
		}

		// Compare the new scan results to the last one saved
		for (ScanResult newResult : results) {
			for (ScanResult savedResult: this.lastResults)
				if (newResult.BSSID.compareTo(savedResult.BSSID) == 0){
					stored++;
				}
		}

		// extend the time according to the percent of wifi matches.
		if (this.lastResults.size() == stored){
			Log.i (TAG, "Did not move - extending wifi time");
			this.wifiScanInterval = (long) (this.wifiScanInterval * SAME_LOCATION_MULTIPLIER);

			// If the device has not moved for a long time
			if (this.wifiScanInterval > MAX_WIFI_TIMEOUT){
				Log.i (TAG, "Did not move for a long time - Wifi Disabled");
				this.wifiScanInterval = -1;
			}
			return;
		} 

		// If the device moved by not much
		if (((double)stored/(double)this.lastResults.size()) > MATCH_TRESH_PERCENT){
			Log.i (TAG, "Close location - extending wifi time");
			this.wifiScanInterval = (long) (this.wifiScanInterval * CLOSE_LOCATION_MULTIPLIER);

			Log.i (TAG, "New Wifi Time " + wifiScanInterval );
			
			// If the device has not moved for a long time
			if (this.wifiScanInterval > MAX_WIFI_TIMEOUT){
					Log.i (TAG, "Did not move for a long time - Wifi Disabled");
					this.wifiScanInterval = -1;
			}
			return;
		}

		// Need to reset the time interval.
		this.wifiScanInterval = DEFAULT_SCAN_TIME;
	}

	/**
	 * 
	 * @return
	 */
	public boolean getWifiStayOnStatus() {
		if (this.wifiScanInterval < 0){
			return false;
		}
		return true;
	}

	/*
	 * 
	 */
	public void evaluateGPS(Location mylocation) {
		Log.i (TAG, "Evaluating GPS");
		
		if (null == this.lastLocation){
			this.lastLocation = mylocation;
		}

		if (this.lastLocation.distanceTo(mylocation) < GPS_MIN_DISTANCE){
			Log.i (TAG, "Close Location");
			this.minTime = (long) (this.minTime * CLOSE_LOCATION_MULTIPLIER);
			this.minDistance = (long) (this.minDistance * CLOSE_LOCATION_MULTIPLIER);
		} else {
			this.minTime = this.minTime / 2;
		}

		if (this.minTime == 0)
			this.minTime = 1;
		
		Log.i(TAG, "Set GPS time to " + this.minTime);
		Log.i(TAG, "Set GPS distance to " + this.minDistance);
		
		if (this.minTime > GPS_MAX_UPDATE_TIME){
			Log.i(TAG, "Disable GPS Location");
			this.gps_disable  = true;
		}
	}

	/**
	 * 
	 */
	public void GPSEnable(){
		minTime = 1;
		minDistance = 1;
		this.gps_disable  = true;
	}	

	public boolean GPSStayOnStatus(){
		return this.gps_disable;
	}
}